import { searchWeiboByKeyword, getWeiboDetail, getUserInfo, extractWeiboDetailLinks, WeiboSearchOptions } from '@roasmax/weibo-scraper'
import { getBrowserPoolManager } from '@roasmax/browser'
import dayjs from 'dayjs'
import { useEntityManager } from '../storage/data-source';
import { KeywordCrawlWindow, User, WeiboData } from '../storage/entities';
import { v4 } from 'uuid';
import { from, concatMap, catchError, EMPTY } from 'rxjs'
import { RabbitMQManager } from '../core/rabbitmq-manager';
import { logger } from '@roasmax/logger';
export async function searchTaskExecutor(keyword: string, cookies: string) {
    // 根据 keyword 检查时间信息
    const keywordCrawlWindow = await getKeywordCrawlWindow(keyword)
    if (!keywordCrawlWindow) {
        // 首次爬取
        await createKeywordCrawlWindow(keyword)
        return await creawlLatestWeiboByKeyword(keyword, cookies)
    } else {
        const nextHourDate = dayjs().add(1, 'hour').toDate();
        if (keywordCrawlWindow.startTime && keywordCrawlWindow.endTime) {
            if (keywordCrawlWindow.hasMoreHistory) {
                // 检索历史消息
                return creawlLatestWeiboByKeyword(keyword, cookies, { endTime: keywordCrawlWindow.startTime })
            }
            else if (keywordCrawlWindow.endTime > nextHourDate) {
                // 检索最新
                return creawlLatestWeiboByKeyword(keyword, cookies, { startTime: keywordCrawlWindow.endTime })
            }
            throw new Error(`searchTaskExecutor error`)
        } else {
            return await creawlLatestWeiboByKeyword(keyword, cookies)
        }
    }
}
const formatTime = (date: Date): string => {
    const year = date.getFullYear()
    const month = String(date.getMonth() + 1).padStart(2, '0')
    const day = String(date.getDate()).padStart(2, '0')
    const hour = String(date.getHours()).padStart(2, '0')
    return `${year}-${month}-${day}-${hour}`
}
export async function creawlLatestWeiboByKeyword(keyword: string, cookies: string, timeRange: { startTime?: Date, endTime?: Date } = {}) {
    // https://s.weibo.com/weibo?q=%E8%AD%A6%E6%96%B9%E9%80%9A%E6%8A%A5%E6%B2%B3%E5%8C%97%E4%B8%80%E5%A5%B3%E5%AD%90%E7%96%91%E5%AE%B6%E6%9A%B4%E5%8E%BB%E4%B8%96&typeall=1&suball=1&Refer=g&page=1&timescope=custom%3A2009-08-16-0%3A2025-08-24-3
    const options: WeiboSearchOptions = { startPage: 1, cookies: cookies }
    if (timeRange && timeRange.startTime) {
        options.startTime = formatTime(timeRange.startTime)
    }
    if (timeRange && timeRange.endTime) {
        options.endTime = formatTime(timeRange.endTime)
    }
    const pageInfo = await searchWeiboByKeyword(keyword, options)
    const browserPoolManager = getBrowserPoolManager()
    const sessionId = v4()
    const rabbitmqManager = RabbitMQManager.getInstance()
    const subscription = from(pageInfo.pageUrls).pipe(
        // 使用 concatMap 保证页面按顺序处理
        concatMap(async pageUrl => {
            const html = await browserPoolManager.getHtml(sessionId, pageUrl, cookies)
            const links = extractWeiboDetailLinks(html)
            if (links.length === 0) {
                if (options.endTime) {
                    // 历史数据
                    let keywordCrawlWindow = await getKeywordCrawlWindow(keyword)
                    if (!keywordCrawlWindow) {
                        keywordCrawlWindow = await createKeywordCrawlWindow(keyword)
                    }
                    await useEntityManager(async m => {
                        await m.update(KeywordCrawlWindow, keywordCrawlWindow.keyword, {
                            hasMoreHistory: false
                        })
                    })
                }
                logger.info(`page url is ${pageUrl}`)
            }
            return links;
        }),
        // 再次使用 concatMap 来处理从页面中提取的链接，保证所有微博都按顺序处理
        concatMap(weiboLinks => from(weiboLinks)),
        concatMap(async (detailLink) => {
            try {
                // 依次获取API数据
                const detail: any = await getWeiboDetail({ id: detailLink.mid, cookies: cookies })
                const userInfoResponse = await getUserInfo({ uid: detailLink.uid, cookies: cookies });
                const user = userInfoResponse.data.user;

                let keywordCrawlWindow = await getKeywordCrawlWindow(keyword)
                if (!keywordCrawlWindow) {
                    keywordCrawlWindow = await createKeywordCrawlWindow(keyword)
                }

                await useEntityManager(async m => {
                    const weiboDataRepo = m.getRepository(WeiboData);
                    const userRepo = m.getRepository(User);

                    // 1. 保存或更新用户信息
                    let userEntity = await userRepo.findOne({ where: { uid: user.idstr } });
                    if (!userEntity) {
                        userEntity = new User();
                        userEntity.uid = user.idstr;
                    }
                    userEntity.nickname = user.screen_name;
                    userEntity.avatar = user.avatar_hd;
                    userEntity.isVip = user.vvip === 1 || user.mbtype > 1;
                    userEntity.followersCount = user.followers_count;
                    userEntity.followingCount = user.friends_count;
                    userEntity.statusesCount = user.statuses_count;
                    userEntity.description = user.description;
                    userEntity.location = user.location;
                    userEntity.verifiedType = user.verified_type;
                    // user.verified_reason is not available in the base user info, only in post-specific user objects
                    await userRepo.save(userEntity);

                    // 2. 保存微博详情
                    let weiboDataEntity = await weiboDataRepo.findOne({ where: { weiboId: detail.mid } });
                    if (!weiboDataEntity) {
                        weiboDataEntity = new WeiboData();
                        weiboDataEntity.weiboId = detail.mid;
                    }
                    weiboDataEntity.text = detail.text_raw;
                    weiboDataEntity.userId = detail.user.idstr;
                    weiboDataEntity.userNickname = detail.user.screen_name;
                    weiboDataEntity.userAvatar = detail.user.avatar_hd;
                    weiboDataEntity.source = detail.source;
                    weiboDataEntity.repostsCount = detail.reposts_count;
                    weiboDataEntity.commentsCount = detail.comments_count;
                    weiboDataEntity.likesCount = detail.attitudes_count;
                    weiboDataEntity.isRepost = !!detail.retweeted_status;
                    if (detail.retweeted_status) {
                        weiboDataEntity.originalWeiboId = detail.retweeted_status.mid;
                    }
                    weiboDataEntity.publishedAt = new Date(detail.created_at);
                    await weiboDataRepo.save(weiboDataEntity);

                    // 3. 依次发送MQ消息
                    await rabbitmqManager.sendWeiboDetailMessage(detail);
                    await rabbitmqManager.sendWeiboAccountMessage(user);

                    // 更新时间窗口
                    const createdAt = new Date(detail.created_at)
                    const currentStartTime = keywordCrawlWindow.startTime
                    const currentEndTime = keywordCrawlWindow.endTime

                    const newStartTime = !currentStartTime || createdAt < currentStartTime
                        ? createdAt
                        : currentStartTime

                    const newEndTime = !currentEndTime || createdAt > currentEndTime
                        ? createdAt
                        : currentEndTime

                    await m.update(KeywordCrawlWindow, keywordCrawlWindow.keyword, {
                        startTime: newStartTime,
                        endTime: newEndTime,
                        totalPostsCrawled: keywordCrawlWindow.totalPostsCrawled + 1,
                        lastHistoryCrawlAt: new Date(),
                    })
                })

                return { success: true, mid: detailLink.mid };
            } catch (error) {
                const errorMessage = error instanceof Error ? error.message : String(error);
                console.error(`处理微博 ${detailLink.mid} 时出错:`, error);
                return { success: false, mid: detailLink.mid, error: errorMessage };
            }
        }),
        catchError((error) => {
            console.error('微博处理流出现意外错误:', error);
            return EMPTY;
        })
    )
    return subscription
}

export async function getKeywordCrawlWindow(keyword: string): Promise<KeywordCrawlWindow | null> {
    return await useEntityManager(async (manager) => {
        const repo = manager.getRepository(KeywordCrawlWindow)
        return await repo.findOne({ where: { keyword } })
    })
}

export async function createKeywordCrawlWindow(keyword: string) {
    return await useEntityManager(async (manager) => {
        const repo = manager.getRepository(KeywordCrawlWindow)
        const window = new KeywordCrawlWindow()
        window.keyword = keyword
        window.hasMoreHistory = true
        window.totalPostsCrawled = 0
        window.latestPostsCrawled = 0
        window.historyPostsCrawled = 0
        await repo.save(window)
        return window
    })
}